package org.bminfo.migle.parser;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.biojava.bio.seq.Sequence;
import org.bminfo.sequence.FastaSeq;
import org.bminfo.sequence.RawInput;
import org.bminfo.migle.format.Iupac;

public class PointMut {

	public String miGLE_home = "";
	public String moopPath = "";
	String tempRoot = "";
	String folderName;
	public String tempPath;
	
	public void setPointMutPath(String path, String foldername){

		miGLE_home = path.replace("\\", "/");
		moopPath = miGLE_home + "WEB-INF/classes/org/bminfo/migle/miGLE/";
		tempRoot = miGLE_home + "temp/";
		
		folderName = foldername;
		tempPath = tempRoot + folderName + "/";	
		
//		System.out.println(foldername);
//		System.out.println(folderName);
//		System.out.println(tempPath);
	}
	
//	public static void main(String[] args) {
//		String infile = "3utr.fasta";
//
//		FastaSeq fasta = new FastaSeq(infile, "DNA");
//
//		String seq = fasta.GetFirstSequence().seqString();
//		String title = fasta.GetFirstSequence().getName();
//		System.out.println(fasta.GetFirstSequence().getName());
//
//		HashMap<String, String> snpInfo = getAllelesType(title);
//
//		PointMut pm = new PointMut();
//
//		pm.buildAnalysisFile(title, seq, snpInfo, "");
//		//		pm.Analysis(infile,242, 262, "./", "G");
//
//	}
	
	public void pointMut(int site, String iupac_char, String filetype, String indel, String indel_string) throws IOException{
		
		System.out.println(tempPath);
		
		Map<String, String> iupac = new HashMap<String,String>();
		iupac.put("A", "A");
		iupac.put("C", "C");
		iupac.put("G", "G");
		iupac.put("T", "T");
		iupac.put("M", "AC");
		iupac.put("R", "AG");
		iupac.put("W", "AT");
		iupac.put("S", "CG");
		iupac.put("Y", "CT");
		iupac.put("K", "GT");
		iupac.put("V", "ACG");
		iupac.put("H", "ACT");
		iupac.put("D", "AGT");
		iupac.put("B", "CGT");
		iupac.put("N", "ACGT");
		
//		>rs5186|miGLE|SNP|site=301|length=601|alleles=A/C|Origin
//		gtatagcttattttaacaattgcctgaatcctcttttttatggctttctggggaaaaaatttaaaagatattttctccagcttctaaaatatattcccccaaaagccaaatcccactcaaacctttcaacaaaaatgagcacgctttcctaccgcccctcagataatgtaagctcatccaccaagaagcctgcaccatgttttgaggttgagtgacatgttcgaaacctgtccataaagtaattttgtgaaagaaggagcaagagaacattcctctgcagcacttcactaccaaatgagcattagctacttttcagaattgaaggagaaaatgcattatgtggactgaaccgacttttctaaagctctgaacaaaagcttttctttccttttgcaacaagacaaagcaaagccacattttgcattagacagatgacggctgctcgaagaacaatgtcagaaactcgatgaatgtgttgatttgagaaattttactgacagaaatgcaatctccctagcctgcttttgtcctgttattttttatttccacataaaggtatttagaatatattaaatcgttagaggagcaacaggagatgaga
//
//		>291|c->A|pointMut
//		aagagaacattcctctgcagcacttcactaAcaaatgagcattagctacttttcagaattg
//		>291|c->T|pointMut
//		aagagaacattcctctgcagcacttcactaTcaaatgagcattagctacttttcagaattg
//		>291|c->G|pointMut
//		aagagaacattcctctgcagcacttcactaGcaaatgagcattagctacttttcagaattg
		
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(tempPath + "seq.fasta" )));
		PrintWriter wr = new PrintWriter(new BufferedWriter(new FileWriter(tempPath + "pointmut")));
		
		String line = null;
		String head = "";
        StringBuilder seq = new StringBuilder();
       	int startSeq = 1;
		
//        >gi|122939142|miGLE|3'UTR|Start=1081|Length=894|CodonStart|1|CdsLength|1080 
        
		while((line = br.readLine()) != null){
			if(line.startsWith(">")){
				head = line + "|Origin";
			}else{
				seq.append(line.toLowerCase());
			}
		}

		if(head.contains("|miGLE|3\'UTR|")){
			String[] field = head.split("\\|");
			startSeq = Integer.parseInt(field[4].replace("Start=", ""));
		}
		
   		String sequence = seq.toString();
   		int length = sequence.length();
   		int startRange = site-10;
       	int endRange = site+10;

       	if(startRange < startSeq){
       		startRange = startSeq;
       	}
       	if(endRange > (startSeq + length -1)){
       		endRange = startSeq + length -1;
       	}
       	
       	int windowLength = 30;
 		
		wr.write(head + "\n");
		wr.write(sequence + "\n\n");
		
       	if(indel.equals("insert")){
       		int mutStart = site - windowLength;
       		int mutEnd = site + windowLength;
       		
           	if(mutStart < startSeq){
           		mutStart = startSeq;
           	}
           	if(mutEnd > (startSeq + length -1)){
           		mutEnd = startSeq + length -1;
           	}
           	
           	String range = sequence.substring(mutStart-startSeq, mutEnd-startSeq+1);
           	
           	wr.write(">" + site + "|" + "N" + "->" + "\'-\'" + "|pointMut\n");
           	wr.write(range + "\n");
           	
   			range = sequence.substring(mutStart-startSeq, site-startSeq)
           				+ indel_string
           				+ sequence.substring(site-startSeq+1, mutEnd-startSeq+1);
           	wr.write(">" + site + "|" + "N" + "->" + indel_string + "|pointMut\n");
           	wr.write(range + "\n");
       		wr.write("\n");
       	}else {
       	
       	for(int i=startRange; i<=endRange; i++ ){
       		
       		int mutStart = i - windowLength;
       		int mutEnd = i + windowLength;
       		
           	if(mutStart < startSeq){
           		mutStart = startSeq;
           	}
           	if(mutEnd > (startSeq + length -1)){
           		mutEnd = startSeq + length -1;
           	}
           	
           	if(filetype.equals("snp") && i == site){
           		String iupac_list = iupac.get(iupac_char);
           		for(int j=0; j<iupac_list.length(); j++){
           			if(iupac_list.toLowerCase().charAt(j) != sequence.charAt(i-startSeq)){
           				String range = sequence.substring(mutStart-startSeq, i-startSeq)
           						+ iupac_list.charAt(j)
           						+ sequence.substring(i-startSeq+1, mutEnd-startSeq+1);
           				wr.write(">" + i + "|" + sequence.charAt(i-startSeq) + "->" + iupac_list.charAt(j) + "|pointMut\n");
           				wr.write(range + "\n");
           				wr.flush();
           			}
           		}
           		wr.write("\n");
           	}else{
           		String atgc_list = "ATGC";
           		for(int j=0; j<atgc_list.length(); j++){
           			if(atgc_list.toLowerCase().charAt(j) != sequence.charAt(i-startSeq)){
           				String range = sequence.substring(mutStart-startSeq, i-startSeq)
           						+ atgc_list.charAt(j)
           						+ sequence.substring(i-startSeq+1, mutEnd-startSeq+1);
           				wr.write(">" + i + "|" + sequence.charAt(i-startSeq) + "->" + atgc_list.charAt(j) + "|pointMut\n");
           				wr.write(range + "\n");
           				wr.flush();
           			}
           		}
           		wr.write("\n");
           	}
       	}
       	}
       	
       	br.close();
       	wr.close();

	}
	
	public void buildAnalysisFile(String path, String title, String seq,
			HashMap<String, String> snpInfo, String referenceAllele) {
		RawInput rin = new RawInput();


		String seqPos = snpInfo.get("position");
		String alleleInfo = snpInfo.get("alleles");

		String[] fields = alleleInfo.split("/");
		if(fields.length < 2){
			System.out.println(alleleInfo);
			return;
		}
		String outfile = path + "pointmut";
		rin.CreateFile(outfile);

		int javaIndex = Integer.parseInt(seqPos)-1;

		int referenceIndex = 0;
		//get reference alleles id
		
		for(int i=0; i< fields.length; i++){
			if(fields[i].equalsIgnoreCase(referenceAllele)){
				referenceIndex = i;
				break;
			}
		}

		//output reference sequence
		rin.WriteFile(outfile, ">" + title + "|Reference\n");
		String refAllele = fields[referenceIndex].equals("-")?"":fields[referenceIndex];
		rin.WriteFile(outfile, seq.substring(0, javaIndex) + "\n" +
				refAllele + "\n" + seq.substring(javaIndex + 1));
		
		int mut_num = 1;

		for(int i = 0; i < fields.length; i++){
			if(i == referenceIndex)
				continue;

			System.out.println("writing");
			rin.WriteFile(outfile, ">" + title + "|mut" + mut_num++ + "\n");
			rin.WriteFile(outfile, seq.substring(0, javaIndex) +"\n" +
					fields[i] + "\n" +seq.substring(javaIndex + 1));
		}

		rin.CloseFile(outfile);

	}
	public static HashMap<String, String> getAllelesType(String title) {
		Pattern psnpClass = Pattern.compile("\\|snpclass=(\\d+)\\|");
		Pattern pAlleles = Pattern.compile("\\|alleles='(.*?)'\\|");
		Pattern pAllelePos = Pattern.compile("\\|allelePos=(\\d+)\\|");

		String type = "";
		String alleles = "";

		Matcher msnpClass = psnpClass.matcher(title);
		Matcher mAlleles = pAlleles.matcher(title);
		if(msnpClass.find()){
			type = msnpClass.group(1);
		}
		if(mAlleles.find()){
			alleles = mAlleles.group(1);
		}

		String position = "";
		Matcher mAllelePos = pAllelePos.matcher(title);
		if(mAllelePos.find()){
			position = mAllelePos.group(1);
		}

		HashMap<String, String> snpType = new HashMap<String, String>();
		snpType.put("type", type);
		snpType.put("alleles", alleles);
		snpType.put("position", position);
		
		String[] fields = alleles.split("/");
		int maxAlleleLength = 0;
		for(int i=0; i< fields.length; i++){
			if(fields[i].length() > maxAlleleLength)
				maxAlleleLength = fields[i].length();
		}
		
		snpType.put("maxAlleleLenght", Integer.toString(maxAlleleLength));

		return snpType;
	}
	private int windowSize = 30;
	private HashMap<String, String> iupac;	

	/**
	 * @param windowSize
	 */
	public PointMut() {

		iupac = new HashMap<String, String>();		
		iupac.put("A" , "A");
		iupac.put("C" , "C");
		iupac.put("G" , "G");
		iupac.put("T" , "T");
		iupac.put("M" , "AC");
		iupac.put("R" , "AG");
		iupac.put("W" , "AT");
		iupac.put("S" , "CG");
		iupac.put("Y" , "CT");
		iupac.put("K" , "GT");
		iupac.put("V" , "ACG");
		iupac.put("H" , "ACT");
		iupac.put("D" , "AGT");
		iupac.put("B" , "CGT");
		iupac.put("N" , "GATC");
	}
	/*
	 * Definition: Generate point mutation file
	 */
	public void Analysis(String fnaFile, int start, int end, String tempPath, String SingleBaseFromATCG ) {
		if(!tempPath.endsWith("/"))
		{
			tempPath += "/";
		}
		String outfile = tempPath + "pointmut";
		RawInput rin = new RawInput();
		rin.CreateFile(outfile);
		FastaSeq seq = new FastaSeq(fnaFile, "DNA");
		String singleSeq = seq.GetFirstSequence().seqString();
		System.out.println(singleSeq.substring(251, 252));

		int left = start -1;
		System.out.println(left);
		int right = end -1;
		left  = Math.max(0, left);
		right = Math.min(right, singleSeq.length() -1);

		int middle = (left + right)/2;
		System.out.println(middle);
		String singleBase = singleSeq.substring(middle, middle + 1);
		System.out.println(singleBase);

		String mutSpace = this.iupac.get(singleBase.toUpperCase());
		System.out.println("-" + mutSpace + "-");

		String[] fields = mutSpace.split("");
		System.out.println(fields.length);
		//		for(int i =1; i< fields.length; i++){
		//			singleBase = fields[i];
		String leftFlanking = this.GetLeftFlanking(singleSeq, 0, middle);
		String rightFlanking = this.GetRightFlanking(singleSeq, singleSeq.length()-1, middle);

		String refseq = leftFlanking + singleBase + rightFlanking;
		System.out.println(refseq);
		for(int j = left; j<=right; j++){
			String base = refseq.substring(j, j+1);

			String originWindow = GetOriginWindow(refseq, j);
			String title = ">" + Integer.toString(j+1) + "|"+ base  + "|origin";
			System.out.println(title);
			System.out.println(originWindow);
			//					rin.WriteFile(outfile, title);
			//					rin.WriteFile(outfile, originWindow);

			String[] ATCG = {"", "A", "T", "C","G"};
			System.out.println(base.toUpperCase());
			if(iupac.containsKey(base.toUpperCase())){
				if(iupac.get(base.toUpperCase()).length() > 1){
					ATCG = null;
					ATCG = iupac.get(base.toUpperCase()).split("");
					//					rin.GetInput();
				}
			}
			for(int m = 1; m <ATCG.length; m++){
				if(ATCG[m].equals(SingleBaseFromATCG.toUpperCase())){
					continue;
				}
				title = ">" + Integer.toString(j+1) + "|"+ base + "->" + ATCG[m] + "|pointMut";
				System.out.println(">" + Integer.toString(j+1) + "|"+ base + "->" + ATCG[m] + "|pointMut");
				System.out.println(GetMutWindow(refseq, j+1 , ATCG[m]));
				String mutWindow = GetMutWindow(refseq, j+1 , ATCG[m]);
				rin.WriteFile(outfile, title);
				rin.WriteFile(outfile, mutWindow);
			}

		}
		//		}
		rin.CloseFile(outfile);
	}
	private String GetLeftFlanking(String seq, int left, int middle) {
		String leftFlanking = "";
		if(middle > left)
			leftFlanking = seq.substring(left, middle);
		return leftFlanking;
	}

	private String GetRightFlanking(String seq, int right, int middle) {
		String flanking = "";
		if(middle < right)
			flanking = seq.substring(middle +1, right+1);
		return flanking;
	}
	/*
	 * Seuquence mutation simulation:
	 * 1 flanking sequence: ->ATCG
	 * 2 focus position: IUPAC
	 * Assumption: middle base could be IUPAC; flanking only ATCG
	 */
	private String GetMutWindow(String seq, int middle, String mut) {

		int left = middle - windowSize;
		int right = middle + windowSize;
		left = Math.max(0, left -1);
		right = Math.min(right-1, seq.length() -1);

		//	convert to java string count scale
		middle = middle -1;

		String leftFlanking = this.GetLeftFlanking(seq, left, middle);
		String rightFlanking = this.GetRightFlanking(seq, right, middle);

		return leftFlanking + mut + rightFlanking;
	}
	/*
	 * Definition: get sequence window.
	 * 
	 */
	private String GetOriginWindow(String refseq, int middle) {
		int left = middle - windowSize;
		int right = middle + windowSize + 1;
		left = Math.max(0, left);
		right = Math.min(right, refseq.length() -1);		

		return refseq.substring(left, right);
	}



}
